# _*_ coding:utf-8 _*_
# @Time  : 2023.05.29
# @Author: zizlee
import datetime
from typing import Union
from fastapi import APIRouter, Body, Query
from pydantic import BaseModel, validator, constr, conint
from utils import datetime_utils
from db_utils import BaseDatabaseConnection
from constant.user import UserType
from response import APIResponse

from utils.encrypt import Encrypt


class LoginUserItem(BaseModel):
    username: str
    password: str


class UserItem(BaseModel):
    phone: str
    nickname: str
    username: str
    company: str
    job: str
    vip_expire: str
    user_type: int
    service: str
    is_employee: bool
    has_futures_account: bool
    probation_expire: Union[str, None]

    @validator('vip_expire')
    def validate_vip_expire(cls, value):
        time = datetime_utils.auth_yyyy_mm_dd(value)
        if not time:
            raise ValueError('vip_expire formate Error: 接受`YYYY-MM-DD`')
        return time

    @validator('user_type')
    def validate_user_type(cls, value):
        if value not in UserType.USER_TYPES.keys():
            raise ValueError('user_type invalid!')
        return value

    @validator('probation_expire')
    def validate_probation_expire(cls, value):
        return datetime_utils.auth_yyyy_mm_dd(value)
        # if not time:
        #     raise ValueError('probation_expire formate Error: 接受`YYYY-MM-DD`')
        # return time


class CreateUserItem(UserItem):
    password: constr(min_length=6, max_length=20)


class UpdateUserItem(UserItem):
    uid: int
    password: str = None
    is_active: conint(ge=0, le=1)


class UserAdmin:
    def __init__(self, uid: int = None):
        self.uid = uid

    def login(self, account: LoginUserItem):
        with BaseDatabaseConnection() as conn:
            conn.cursor.execute("SELECT id,password,username,ssn,phone,nickname FROM ruizhi_user WHERE (ssn=%s OR phone=%s) AND is_admin=1 AND is_active=1;",
                                [account.username, account.username])
            u = conn.cursor.fetchone()
        if not u:
            return APIResponse.validate_error(detail='用户不存在(用户名或密码错误,失效,非管理员)')
        if not Encrypt.password_verify(account.password, u['password']):
            return APIResponse.validate_error(detail='用户名或密码错误!')
        data = {
            'username': u['username'],
            'role': '',
            'roleId': 0,
            'permissions': [],
            'nickname': u['nickname'],
            'phone': u['phone'],
            'ssn': u['ssn']
        }
        return APIResponse.success(data=data)

    def phone_exist(self, phone: str):
        if not phone:
            return False
        with BaseDatabaseConnection() as conn:
            conn.cursor.execute("SELECT id FROM ruizhi_user WHERE phone=%s LIMIT 1;", [phone])
            exist = conn.cursor.fetchone()
        return True if exist else False

    def create_user(self, user: CreateUserItem):
        if user.phone and self.phone_exist(user.phone):
            return APIResponse.validate_error(detail='手机已存在!')
        ssn = Encrypt.random_string(length=10)
        password_hash = Encrypt.password_hash(password=user.password)
        nickname = user.nickname if user.nickname.strip() else f'智者{ssn[:6]}'
        sql = """
            INSERT INTO ruizhi_user(ssn,phone,nickname,username,company,job,vip_expire,password,user_type,service,has_futures_account,is_employee,
            probation_expire) 
            VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s);
        """
        with BaseDatabaseConnection() as conn:
            count = conn.cursor.execute(sql, [ssn, user.phone, nickname, user.username, user.company, user.job,
                                        user.vip_expire, password_hash, UserType.PROBATION_USER, user.service, user.has_futures_account,
                                              user.is_employee, user.probation_expire])  # 系统添加的是试用用户
        return APIResponse.success(msg='新建用户成功!') if count else APIResponse.validate_error(detail='创建失败，请尝试重新发起!')

    def retrieve_user(self, keyword: str, page: int = 1, page_size: int = 30):
        sql = """
            SELECT id,ssn,phone,nickname,username,user_type,company,job,vip_expire,
            has_futures_account,probation_expire,is_employee,service,is_active,user_type,is_admin 
            FROM ruizhi_user 
        """
        with BaseDatabaseConnection() as conn:
            if keyword:
                sql += 'WHERE ssn=%s OR phone=%s;'
                prm = [keyword, keyword]
            else:
                sql += ';'
                prm = []
            ret = conn.query_paginator(sql, prm, page=page, page_size=page_size)
        for u in ret['rows']:
            u['ut_name'] = UserType.user_type(u['user_type'])
        return APIResponse.success(data=ret)

    def update_user(self, user: UpdateUserItem):
        if user.user_type == UserType.OFFICIAL_USER:
            probation_expire = None
        else:
            probation_expire = user.probation_expire
        if user.user_type == UserType.PROBATION_USER and not user.probation_expire:
            return APIResponse.validate_error(detail='试用用户请设置试用到期日!')
        sql = """
            UPDATE ruizhi_user SET phone=%s,nickname=%s,username=%s,company=%s,job=%s,vip_expire=%s,is_employee=%s,
            service=%s,has_futures_account=%s,probation_expire=%s,is_active=%s,user_type=%s
            WHERE id=%s LIMIT 1;
        """
        prm = [user.phone, user.nickname, user.username, user.company, user.job, user.vip_expire, user.is_employee, user.service,
               user.has_futures_account, probation_expire, user.is_active, user.user_type, user.uid]
        psd_len = len(user.password.strip())
        if 0 < psd_len < 6 or psd_len > 20:
            return APIResponse.validate_error(detail='密码需为6-20位之间的字符')
        if psd_len > 0:
            # 修改密码
            password_hash = Encrypt.password_hash(user.password.strip())
            sql = """
                UPDATE ruizhi_user SET phone=%s,nickname=%s,username=%s,company=%s,job=%s,vip_expire=%s,is_employee=%s,
                service=%s,has_futures_account=%s,probation_expire=%s,is_active=%s,password=%s
                WHERE id=%s LIMIT 1;
            """
            prm = [user.phone, user.nickname, user.username, user.company, user.job, user.vip_expire, user.is_employee, user.service,
                   user.has_futures_account, probation_expire, user.is_active, password_hash,
                   user.uid]
        with BaseDatabaseConnection() as conn:
            conn.cursor.execute(sql, prm)
        return APIResponse.success(msg='修改用户信息成功!')

    def user_count(self):
        start_date = datetime_utils.interval_days(datetime.date.today(), days=-90, link='-', obj=False)
        # 查询用户数
        with BaseDatabaseConnection() as conn:
            conn.cursor.execute("SELECT user_type,COUNT(id) As total FROM ruizhi_user GROUP BY user_type;")
            type_count = list(conn.cursor.fetchall())
            # 查询活跃数据
            conn.cursor.execute("SELECT create_time,user_id FROM ruizhi_user_login WHERE create_time>=%s;", [f'{start_date} 00:00:00'])
            login_rows = list(conn.cursor.fetchall())

        for ut in type_count:
            ut['ut_name'] = UserType.user_type(ut['user_type'])

        user_login = []
        login_count = {}
        for ul in login_rows:
            u_date = ul['create_time'][:10]
            record = (u_date, ul['user_id'])
            if record not in user_login:
                user_login.append(record)
                login_count.setdefault(u_date, 0)
                login_count[u_date] += 1
        date_counts = []
        today_count = 0
        for k, v in login_count.items():
            date_counts.append({'login_date': k, 'total': v})
            if k == datetime_utils.now_yyyy_mm_dd():
                today_count = v

        return APIResponse.success(data={'type_counts': type_count, 'date_counts': date_counts, 'today_count': today_count})


class UserLog:
    def user_login_log(self, user_id: int, page: int, page_size: int = 50):
        sql = """
            SELECT a.create_time,a.user_id,a.origin_ip,a.country,a.province,a.city,a.district,a.isp_name
            FROM ruizhi_user_login As a 
            INNER JOIN ruizhi_user As b ON a.user_id=b.id
            WHERE a.user_id=%s
            ORDER BY a.create_time DESC;
        """
        with BaseDatabaseConnection() as conn:
            ret = conn.query_paginator(sql, param=[user_id], page=page, page_size=page_size)
        return APIResponse.success(data=ret)

    def user_day_active(self, q_date: str = None):
        if not q_date:
            q_date = datetime_utils.now_yyyy_mm_dd()

        sql = """
            SELECT a.create_time,a.active_type,a.description,a.remain,a.cumulative,a.conn_days,a.total_conn_days,
                b.ssn,b.username,b.user_type,b.probation_expire 
            FROM ruizhi_user_activation As a 
            INNER JOIN ruizhi_user As b ON a.user_id=b.id
            WHERE DATE_FORMAT(a.create_time, '%%Y-%%m-%%d')=%s
            ORDER BY a.create_time DESC;
        """
        prm = [q_date]
        with BaseDatabaseConnection() as conn:
            conn.cursor.execute(sql, prm)
            ret = list(conn.cursor.fetchall())
        for row in ret:
            row['ut_name'] = UserType.user_type(row['user_type'])
        return APIResponse.success(data={'records': ret})


user_api = APIRouter()


@user_api.post('/login/')  # 登录
def admin_login(account: LoginUserItem = Body(...)):
    return UserAdmin().login(account=account)


@user_api.post('/create/')
def create_user(user: CreateUserItem = Body(...)):
    return UserAdmin().create_user(user=user)


@user_api.get('/retrieve/')
def retrieve_user(kw: str = Query(...), page: int = Query(1), page_size: int = Query(30)):
    return UserAdmin().retrieve_user(keyword=kw, page=page, page_size=page_size)


@user_api.put('/update/')
def update_user(user: UpdateUserItem = Body(...)):
    return UserAdmin().update_user(user=user)


@user_api.get('/loginLog/')  # 登录记录
def user_login_log(uid: int = Query(...), page: int = Query(...)):
    return UserLog().user_login_log(user_id=uid, page=page)


@user_api.get('/count/')  # 用户数量
def user_count():
    return UserAdmin().user_count()


@user_api.get('/dayActive/')  # 今日活跃
def user_active_today(date: str = Query(None)):
    return UserLog().user_day_active(q_date=date)
